use std::fmt::Debug;

use crate::core::lexer::Lexer;

use super::{invalid_token, Token, TokenType, AST};

#[derive(Clone, Debug, Default)]
pub struct Parser {
    _token_list: Box<Vec<Token>>,
}

fn root_set_ast(root: &mut AST, token_ptr: &mut Vec<Token>, func_ptr: fn(&mut AST, &mut Vec<Token>)) {
    let mut ast = AST::default();
    func_ptr(&mut ast, token_ptr);
    root.children.push(ast);
}

impl Parser {
    #[allow(unused)]
    pub fn new(token_list: Vec<Token>) -> Self {
        Self {
            _token_list: Box::from(token_list)
        }
    }
    #[allow(unused)]
    pub fn syntax_analysis(&mut self) -> AST {
        let token_ptr = self._token_list.as_mut();
        let mut root = AST::default();
        Self::parse(&mut root, token_ptr);
        root
    }

    fn parse(root: &mut AST, token_ptr: &mut Vec<Token>) {
        Self::program(root, token_ptr);
    }
    fn program(root: &mut AST, token_ptr: &mut Vec<Token>) {
        Self::decl_list(root, token_ptr);
    }
    fn ptr_add_one(token_ptr: &mut Vec<Token>) {
        // unsafe {
        //     *token_ptr = token_ptr.add(1);
        // }
        token_ptr.remove(0);
    }
    fn cur_token_type(token_ptr: &Token) -> TokenType {
        // unsafe {token_ptr.read()}.token_type()
        token_ptr.token_type()
    }
    fn match_token(token_type: TokenType, token_ptr: &mut Vec<Token>) {
        if Self::cur_token_type(&token_ptr[0]) == token_type {
            Self::ptr_add_one(token_ptr);
        } else {
            invalid_token(&token_ptr[0]);
        }
    }
    fn decl_list(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::DeclList, "DeclList");
        //first
        root_set_ast(root, token_ptr, Self::decl);

        //push
        while token_ptr.len() > 0 && Self::cur_token_type(&token_ptr[0]) != TokenType::EOF {
            root_set_ast(root, token_ptr, Self::decl);
        }
    }
    fn decl(root: &mut AST, token_ptr: &mut Vec<Token>) {
        let token_type = Self::cur_token_type(&token_ptr[0]);

        if token_type != TokenType::Int && token_type != TokenType::Void {
            invalid_token(&token_ptr[0]);
        }
        let tl1 = token_ptr[1].clone();

        if Self::cur_token_type(&tl1) != TokenType::Id {
            invalid_token(&tl1);
        }
        let tl2 = token_ptr[2].clone();

        if Self::cur_token_type(&tl2) == TokenType::LeftSquareBracket || Self::cur_token_type(&tl2) == TokenType::Semicolon
        {
            Self::var_decl(root, token_ptr);
        } else if Self::cur_token_type(&tl2) == TokenType::LeftRoundBracket {
            Self::func_decl(root, token_ptr);
        } else {
            invalid_token(&tl2);
        }
    }
    fn var_decl(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::VarDecl, "VarDecl");

        root_set_ast(root, token_ptr, Self::_type);

        if Self::cur_token_type(&token_ptr[0]) == TokenType::Id {
            root.children.push(AST::from_token(&token_ptr));
            Self::match_token(TokenType::Id, token_ptr);
        } else {
            invalid_token(&token_ptr[0]);
        }
        
        if Self::cur_token_type(&token_ptr[0]) == TokenType::LeftSquareBracket {
            Self::match_token(TokenType::LeftSquareBracket, token_ptr);

            root.children.push(AST::from_token(&token_ptr));

            Self::match_token(TokenType::Number, token_ptr);
            Self::match_token(TokenType::RightSquareBracket, token_ptr);
        }
        Self::match_token(TokenType::Semicolon, token_ptr);
    }
    fn _type(root: &mut AST, token_ptr: &mut Vec<Token>) {
        let token_type = Self::cur_token_type(&token_ptr[0]);

        if token_type == TokenType::Int || token_type == TokenType::Void {
            *root = AST::from_token(&token_ptr);
            Self::match_token(token_type, token_ptr);
        } else {
            invalid_token(&token_ptr[0])
        }
    }
    fn func_decl(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::FuncDecl, "FuncDecl");

        root_set_ast(root, token_ptr, Self::_type);

        if Self::cur_token_type(&token_ptr[0]) == TokenType::Id {
            root.children
                .push(AST::from_token(&token_ptr));
            Self::match_token(TokenType::Id, token_ptr);
        } else {
            invalid_token(&token_ptr[0]);
        }
        Self::match_token(TokenType::LeftRoundBracket, token_ptr);

        root_set_ast(root, token_ptr, Self::params);

        Self::match_token(TokenType::RightRoundBracket, token_ptr);

        root_set_ast(root, token_ptr, Self::compound_stmt);
    }
    fn params(root: &mut AST, token_ptr: &mut Vec<Token>) {
        let token_type = Self::cur_token_type(&token_ptr[0]);

        if token_type == TokenType::Int || token_type == TokenType::Void {
            Self::param_list(root, token_ptr);
        }
    }
    fn param_list(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::ParamList, "ParamList");

        root_set_ast(root, token_ptr, Self::param);

        while Self::cur_token_type(&token_ptr[0]) == TokenType::Comma {
            Self::match_token(TokenType::Comma, token_ptr);

            root_set_ast(root, token_ptr, Self::param);
        }
    }
    fn param(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::Param, "Param");

        root_set_ast(root, token_ptr, Self::_type);

        if Self::cur_token_type(&token_ptr[0]) == TokenType::Id {
            root.children.push(AST::from_token(&token_ptr));
            Self::match_token(TokenType::Id, token_ptr);
        } else {
            invalid_token(&token_ptr[0]);
        }

        if Self::cur_token_type(&token_ptr[0]) == TokenType::LeftSquareBracket {
            Self::match_token(TokenType::LeftSquareBracket, token_ptr);
            Self::match_token(TokenType::RightSquareBracket, token_ptr);
        }
    }
    fn compound_stmt(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::CompoundStmt, "CompoundStmt");

        Self::match_token(TokenType::LeftCurlyBracket, token_ptr);

        root_set_ast(root, token_ptr, Self::local_decl);
        root_set_ast(root, token_ptr, Self::stmt_list);

        Self::match_token(TokenType::RightCurlyBracket, token_ptr);
    }
    fn local_decl(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::LocalDecl, "LocalDecl");

        while Self::cur_token_type(&token_ptr[0]) == TokenType::Int
            || Self::cur_token_type(&token_ptr[0]) == TokenType::Void
        {
            root_set_ast(root, token_ptr, Self::var_decl);
        }
    }

    fn stmt_list(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::StmtList, "StmtList");

        while Self::cur_token_type(&token_ptr[0]) == TokenType::Semicolon
            || Self::cur_token_type(&token_ptr[0]) == TokenType::Id
            || Self::cur_token_type(&token_ptr[0]) == TokenType::LeftRoundBracket
            || Self::cur_token_type(&token_ptr[0]) == TokenType::Number
            || Self::cur_token_type(&token_ptr[0]) == TokenType::LeftCurlyBracket
            || Self::cur_token_type(&token_ptr[0]) == TokenType::If
            || Self::cur_token_type(&token_ptr[0]) == TokenType::While
            || Self::cur_token_type(&token_ptr[0]) == TokenType::Return
        {
            root_set_ast(root, token_ptr, Self::stmt);
        }
    }

    fn stmt(root: &mut AST, token_ptr: &mut Vec<Token>) {
        let token_type = Self::cur_token_type(&token_ptr[0]);
        match token_type {
            TokenType::Semicolon => {
                Self::expr_stmt(root, token_ptr);
            }
            TokenType::Id => {
                Self::expr_stmt(root, token_ptr);
            }
            TokenType::LeftRoundBracket => {
                Self::expr_stmt(root, token_ptr);
            }
            TokenType::Number => {
                Self::expr_stmt(root, token_ptr);
            }
            TokenType::LeftCurlyBracket => {
                Self::compound_stmt(root, token_ptr);
            }
            TokenType::If => {
                Self::if_stmt(root, token_ptr);
            }
            TokenType::While => {
                Self::while_stmt(root, token_ptr);
            }
            TokenType::Return => {
                Self::return_stmt(root, token_ptr);
            }
            _ => {
                invalid_token(&token_ptr[0]);
            }
        }
    }
    fn expr_stmt(root: &mut AST, token_ptr: &mut Vec<Token>) {
        let token_type = Self::cur_token_type(&token_ptr[0]);
        if token_type == TokenType::Id
            || token_type == TokenType::LeftRoundBracket
            || token_type == TokenType::Number
        {
            Self::expr(root, token_ptr);
        }
        Self::match_token(TokenType::Semicolon, token_ptr);
    }
    fn if_stmt(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::IfStmt, "IfStmt");

        Self::match_token(TokenType::If, token_ptr);
        Self::match_token(TokenType::LeftRoundBracket, token_ptr);

        root_set_ast(root, token_ptr, Self::expr);

        Self::match_token(TokenType::RightRoundBracket, token_ptr);

        root_set_ast(root, token_ptr, Self::stmt);

        let token_type = Self::cur_token_type(&token_ptr[0]);

        if token_type == TokenType::Else {
            Self::match_token(TokenType::Else, token_ptr);
            root_set_ast(root, token_ptr, Self::stmt);
        }
    }

    fn while_stmt(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::WhileStmt, "WhileStmt");

        Self::match_token(TokenType::While, token_ptr);
        Self::match_token(TokenType::LeftRoundBracket, token_ptr);

        root_set_ast(root, token_ptr, Self::expr);

        Self::match_token(TokenType::RightRoundBracket, token_ptr);

        root_set_ast(root, token_ptr, Self::stmt);
    }

    fn return_stmt(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::ReturnStmt, "ReturnStmt");
        Self::match_token(TokenType::Return, token_ptr);
        let token_type = Self::cur_token_type(&token_ptr[0]);
        if token_type == TokenType::Id
            || token_type == TokenType::LeftRoundBracket
            || token_type == TokenType::Number
        {
            root_set_ast(root, token_ptr, Self::expr);
        }
        Self::match_token(TokenType::Semicolon, token_ptr);
    }

    fn expr(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::Expr, "Expr");

        let token_type = Self::cur_token_type(&token_ptr[0]);
        if token_type == TokenType::LeftRoundBracket || token_type == TokenType::Number {
            root_set_ast(root, token_ptr, Self::simple_expr);
            return;
        } else if token_type != TokenType::Id {
            invalid_token(&token_ptr[0]);
        }
        if Self::cur_token_type(&token_ptr[1])
            == TokenType::LeftRoundBracket
        {
            root_set_ast(root, token_ptr, Self::simple_expr);
        } else {
            let bak = token_ptr.clone();

            root_set_ast(root, token_ptr, Self::var);

            let is_assign_bool = Self::cur_token_type(&token_ptr[0]) == TokenType::Assign;
            root.children.pop();

            *token_ptr = bak;

            if is_assign_bool {
                root_set_ast(root, token_ptr, Self::var);
                Self::match_token(TokenType::Assign, token_ptr);
                root_set_ast(root, token_ptr, Self::expr);
            } else {
                root_set_ast(root, token_ptr, Self::simple_expr);
            }
        }
    }

    fn var(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::Var, "Var");
        if Self::cur_token_type(&token_ptr[0]) == TokenType::Id {
            root.children.push(AST::from_token(&token_ptr));
            Self::match_token(TokenType::Id, token_ptr);
        } else {
            invalid_token(&token_ptr[0]);
        }

        if Self::cur_token_type(&token_ptr[0]) == TokenType::LeftSquareBracket {
            Self::match_token(TokenType::LeftSquareBracket, token_ptr);
            root_set_ast(root, token_ptr, Self::expr);
            Self::match_token(TokenType::RightSquareBracket, token_ptr);
        }
    }

    //TODO
    fn simple_expr(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::SimpleExpr, "SimpleExpr");
        root_set_ast(root, token_ptr, Self::add_expr);
        let token_type = Self::cur_token_type(&token_ptr[0]);
        if token_type == TokenType::Less
            || token_type == TokenType::LessEq
            || token_type == TokenType::Greater
            || token_type == TokenType::GreaterEq
            || token_type == TokenType::Eq
            || token_type == TokenType::NotEq
        {
            root_set_ast(root, token_ptr, Self::rel_op);
            root_set_ast(root, token_ptr, Self::add_expr);
        }
    }
    fn rel_op(root: &mut AST, token_ptr: &mut Vec<Token>) {
        let token_type = Self::cur_token_type(&token_ptr[0]);
        if token_type == TokenType::Less
            || token_type == TokenType::LessEq
            || token_type == TokenType::Greater
            || token_type == TokenType::GreaterEq
            || token_type == TokenType::Eq
            || token_type == TokenType::NotEq
        {
            *root = AST::from_token(&token_ptr);
            Self::match_token(Self::cur_token_type(&token_ptr[0]), token_ptr);
        } else {
            invalid_token(&token_ptr[0]);
        }
    }
    /// 从这里开始向下无效
    // fn op_expr(root: &mut AST, token_ptr: &mut Vec<Token>) {
    //     *root = AST::new2(TokenType::OpExpr, "OpExpr");
    //     root_set_ast(root, token_ptr, Self::factor);
    //     while Self::cur_token_type(&token_ptr[0]) == TokenType::Plus
    //         || Self::cur_token_type(&token_ptr[0]) == TokenType::Minus
    //         || Self::cur_token_type(&token_ptr[0]) == TokenType::Multiply
    //         || Self::cur_token_type(&token_ptr[0]) == TokenType::Divide
    //     {
    //         root_set_ast(root, token_ptr, Self::add_expr);
    //         root_set_ast(root, token_ptr, Self::factor);
    //     }
    // }
    // fn op_op(root: &mut AST, token_ptr: &mut Vec<Token>) {
    //     let token_type = Self::cur_token_type(&token_ptr[0]);
    //     if token_type == TokenType::Plus
    //         || token_type == TokenType::Minus
    //         || token_type == TokenType::Multiply
    //         || token_type == TokenType::Divide
    //     {
    //         *root = AST::from_token(&token_ptr);
    //         Self::match_token(token_type, token_ptr);
    //     } else {
    //         invalid_token(&token_ptr[0]);
    //     }
    // }
    /// 无效代码到此处结束
    fn add_expr(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::AddExpr, "AddExpr");
        root_set_ast(root, token_ptr, Self::term);
        while Self::cur_token_type(&token_ptr[0]) == TokenType::Plus || Self::cur_token_type(&token_ptr[0]) == TokenType::Minus {
            root_set_ast(root, token_ptr, Self::add_op);
            root_set_ast(root, token_ptr, Self::term);
        }
    }
    fn add_op(root: &mut AST, token_ptr: &mut Vec<Token>) {
        let token_type = Self::cur_token_type(&token_ptr[0]);
        if token_type == TokenType::Plus || token_type == TokenType::Minus {
            *root = AST::from_token(&token_ptr);
            Self::match_token(token_type, token_ptr);
        } else {
            invalid_token(&token_ptr[0]);
        }
    }
    fn term(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::Term, "Term");
        root_set_ast(root, token_ptr, Self::factor);
        while Self::cur_token_type(&token_ptr[0]) == TokenType::Multiply || Self::cur_token_type(&token_ptr[0]) == TokenType::Divide {
            root_set_ast(root, token_ptr, Self::mul_op);
            root_set_ast(root, token_ptr, Self::factor);
        }
    }

    fn mul_op(root: &mut AST, token_ptr: &mut Vec<Token>) {
        let token_type = Self::cur_token_type(&token_ptr[0]);

        if token_type == TokenType::Multiply || token_type == TokenType::Divide {
            *root = AST::from_token(&token_ptr);
            Self::match_token(token_type, token_ptr);
        } else {
            invalid_token(&token_ptr[0]);
        }
    }
    fn factor(root: &mut AST, token_ptr: &mut Vec<Token>) {
        let token_type = Self::cur_token_type(&token_ptr[0]);
        if token_type == TokenType::LeftRoundBracket {
            Self::match_token(TokenType::LeftRoundBracket, token_ptr);
            Self::expr(root, token_ptr);
            Self::match_token(TokenType::RightRoundBracket, token_ptr);
        } else if token_type == TokenType::Number {
            *root = AST::from_token(&token_ptr);
            Self::match_token(token_type, token_ptr);
        } else if token_type == TokenType::Id {
            if Self::cur_token_type(&token_ptr[1]) == TokenType::LeftRoundBracket
            {
                Self::call(root, token_ptr);
            } else {
                Self::var(root, token_ptr);
            }
        } else {
            invalid_token(&token_ptr[0]);
        }
    }
    fn call(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::Call, "Call");

        let token_type = Self::cur_token_type(&token_ptr[0]);
        if token_type == TokenType::Id {
            root.children.push(AST::from_token(&token_ptr));
            Self::match_token(TokenType::Id, token_ptr);
        } else {
            invalid_token(&token_ptr[0]);
        }
        Self::match_token(TokenType::LeftRoundBracket, token_ptr);

        let token_type = Self::cur_token_type(&token_ptr[0]);
        if token_type == TokenType::Id
            || token_type == TokenType::LeftRoundBracket
            || token_type == TokenType::Number
        {
            root_set_ast(root, token_ptr, Self::arg_list);
        }
        Self::match_token(TokenType::RightRoundBracket, token_ptr);
    }
    fn arg_list(root: &mut AST, token_ptr: &mut Vec<Token>) {
        *root = AST::new2(TokenType::ArgList, "ArgList");
        root_set_ast(root, token_ptr, Self::expr);

        while Self::cur_token_type(&token_ptr[0]) == TokenType::Comma {
            Self::match_token(TokenType::Comma, token_ptr);
            root_set_ast(root, token_ptr, Self::expr);
        }
    }
}

#[test]
pub fn test_this() {
    // v.push("value".to_string());
    // println!("{}", v[1]);
    // println!("Token_size:{:?},ast_size:{}", size_of::<Token>(), size_of::<AST>());
}
